/*
 * Copyright (c) 2007 jNetX.
 * http://www.jnetx.com
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * jNetX. You shall not disclose such Confidential Information and
 * shall use it only in accordance with the terms of the license
 * agreement you entered into with jNetX.
 *
 * $Id$
 */
package com.jnetx.javax.sip.message;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.sip.address.URI;
import javax.sip.message.Request;
import java.text.ParseException;

/**
 * @author <a href="mailto:dparhonin@jnetx.ru">Dmitry Parhonin</a>
 * @version $Revision$
 */
public class SIPRequest extends SIPMessage implements Request {
    private static final Log logger = LogFactory.getLog(SIPRequest.class);

    private String method;
    private URI requestURI;

    public SIPRequest() {
    }

    protected SIPRequest(int numberOfHeaderNames) {
        super(numberOfHeaderNames);
    }

    /**
     * Creates and returns a deep copy of the Message. This methods must ensure a
     * deep copy of the message, so that it can be modified without effecting
     * the original message. This provides useful functionality for proxying
     * Requests and Responses, for example:
     * <ul>
     * <li>Receive a message.
     * <li>Create a deep clone of the message.
     * <li>Modify necessary headers.
     * <li>Proxy the message using the send methods on the SipProvider.
     * </ul>
     * The message contents are cloned as follows:
     * <ul>
     * <li>If the content is of type byte[] a new byte[] array is allocated and the
     * original contents are copied over to the cloned Message.
     * <li>If the content is of type String then a new String equal to the old
     * String is allocated and assigned to the cloned Message.
     * <li>If the content is of type Object and it has a public clone method
     * then it is invoked and the resultant Object is used in the new cloned
     * Message.
     * </ul>
     *
     * @return a deep copy of Message
     */
    public Object clone() {
        final SIPRequest request;
        if (parsed) {
            request = new SIPRequest(getNumberOfHeaderNames());
            request.cloneInternals(this);
            request.cloneHeaders(this);
            request.cloneContent(this);
            request.method = this.method;
            request.requestURI = (URI) this.requestURI.clone();
        } else {
            request = SIPRequest.createLazily(this.messageData);
        }
        return request;
    }

    /**
     * Gets method string of this Request message.
     *
     * @return the method of this Request message.
     */
    public String getMethod() {
        if (!parsed) parse();
        return method;
    }

    /**
     * Sets the method of Request to the newly supplied value. The standard
     * RFC3261 methods are REGISTER for registering contact information, INVITE,
     * ACK, and CANCEL for setting up sessions, BYE for terminating sessions, and
     * OPTIONS for querying servers about their capabilities.
     *
     * @param method the new string value of the method of Request.
     * @throws java.text.ParseException which signals that an error has been reached
     *                                  unexpectedly while parsing the method value.
     */
    public void setMethod(String method) throws ParseException {
        this.method = method;
        invalidateMessageData();
    }

    /**
     * Gets the URI Object identifying the request URI of this Request, which
     * indicates the user or service to which this request is addressed.
     *
     * @return Request URI of Request.
     */
    public URI getRequestURI() {
        if (!parsed) parse();
        return requestURI;
    }

    /**
     * Sets the RequestURI of Request. The Request-URI is a SIP or SIPS URI
     * or a general URI. It indicates the user or service to which this request
     * is being addressed. SIP elements MAY support Request-URIs with schemes
     * other than "sip" and "sips", for example the "tel" URI scheme. SIP
     * elements MAY translate non-SIP URIs using any mechanism at their disposal,
     * resulting in SIP URI, SIPS URI, or some other scheme.
     *
     * @param requestURI the new Request URI of this request message.
     */
    public void setRequestURI(URI requestURI) {
        this.requestURI = requestURI;
        invalidateMessageData();
    }

    public byte[] buildMessageData() {
        final StringBuilder sb = new StringBuilder();
        sb.append(method).append(' ').append(requestURI).append(' ').append(getSIPVersion()).append('\r').append('\n');
        buildMessageHeaders(sb);
        sb.append('\r').append('\n');
        buildMessageContent(sb);
        return sb.toString().getBytes();
    }

    /**
     * This method parses the {@link #messageData}. It is obliged to reset {@link #parsed} indicator.
     */
    protected void parse() {
        parsed = true;
        try {
            SIPRequestParser.parseRequest(messageData, this);
        } catch (ParseException e) {
            logger.error("Cannot parse the SIP request!", e);
        }
    }

    static SIPRequest createLazily(byte[] unparsedData) {
        final SIPRequest request = new SIPRequest();
        request.messageData = unparsedData;
        request.parsed = false;
        return request;
    }
}
/*
 * $Log$
 */